/**
 * 
 */
package com.precisosoft.mathematize.server.handler;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.allen_sauer.gwt.log.client.Log;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.gwtplatform.dispatch.server.ExecutionContext;
import com.gwtplatform.dispatch.server.actionhandler.ActionHandler;
import com.gwtplatform.dispatch.shared.ActionException;
import com.precisosoft.mathematize.server.dao.UserDao;
import com.precisosoft.mathematize.server.domain.User;
import com.precisosoft.mathematize.server.util.Security;
import com.precisosoft.mathematize.shared.action.LoginAction;
import com.precisosoft.mathematize.shared.action.LoginResult;
import com.precisosoft.mathematize.shared.exception.LoginException;

/**
 * @author jewettdx
 * 
 */
public class LoginHandler implements ActionHandler<LoginAction, LoginResult> {

	private final Provider<HttpServletRequest> requestProvider;

	// private final ServletContext servletContext;

	@Inject
	LoginHandler(final ServletContext servletContext,
			final Provider<HttpServletRequest> requestProvider) {
		this.requestProvider = requestProvider;
		// this.servletContext = servletContext;
	}

	@Override
	public LoginResult execute(final LoginAction action,
			final ExecutionContext context) throws ActionException {

		LoginResult result = null;
		UserDao userDao = new UserDao();

		Log.debug("LoginHandler - login: " + action.getLogin() + ", password: "
				+ action.getPassword());

		try {
			User user = null;
			try {
				user = userDao.retrieveUser(action.getLogin());
			} catch (Exception e) {
				e.printStackTrace();
			}

			if (user == null) {
				createDefaultUser();
				user = userDao.retrieveUser(action.getLogin());
			}

			if (user != null && isValidLogin(action, user)) {
				Log.debug(action.getLogin() + " has logged in");

				HttpSession session = requestProvider.get().getSession();
				session.setAttribute("login.authenticated", action.getLogin());

				result = new LoginResult(session.getId());
			} else {
				// GWTP only includes the exception type and it's message?
				// Looks like it needs only a small change on the
				// DispatchServiceImpl class,
				// on the execute() method:
				// Instead of calling logger.warning(message), use
				// logger.log(level, message, throwable).
				throw new LoginException("Invalid User name or Password.");
			}
		} catch (Exception e) {
			throw new ActionException(e);
		}

		return result;
	}

	public void createDefaultUser() {

		User user1 = new User();
		user1.setLogin("Administrator");

		String salt = Security.randomCharString();
		Log.debug("salt: " + salt);

		String password = "N0M0r3$ecrets";
		String hash = Security.sha256(salt + password);
		user1.setSalt(salt);
		user1.setPassword(hash);

		UserDao userDao = new UserDao();
		userDao.createUser(user1);
	}

	private Boolean isValidLogin(LoginAction action, User user) {
		String hash = Security.sha256(user.getSalt() + action.getPassword());

		return hash.equals(user.getPassword());
	}

	@Override
	public Class<LoginAction> getActionType() {
		return LoginAction.class;
	}

	@Override
	public void undo(LoginAction action, LoginResult result,
			ExecutionContext context) throws ActionException {
	}

}
